library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use IEEE.STD_LOGIC_ARITH.ALL; 
use IEEE.STD_LOGIC_UNSIGNED.ALL;
USE ieee.numeric_std.all;
LIBRARY lpm;
USE lpm.lpm_components.ALL;

ENTITY SF_table_interface IS
	GENERIC ( MAC_len: INTEGER:= 6; -- source and destination mac address 6 bytes
			  Input_port_num_bit: INTEGER:= 2;  --2 bits for input port number
			  output_port_num_bit: INTEGER:= 4;	--3 bits for output port number
			  Mac_num_bit: INTEGER:= 8;
			  Counter_num_bit:INTEGER:=4
			  
    );
    Port ( 
		reset:In STD_LOGIC;
		clk : In STD_LOGIC; 
       --data input port number
       Rcv_SportN: In STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0);
       
       --address FIFO signals  		
        Add_Fifo_empty: In STD_LOGIC;
        Add_Fifo_data: In STD_LOGIC_VECTOR(7 downto 0);
        Add_Fifo_rdreq_out : out STD_LOGIC;
       
       --output port number FIFO signals for pfifo
              
		Outp_Fifo_Pdata : Out STD_LOGIC_VECTOR (output_port_num_bit-1 downto 0);
		OutP_Fifo_wreq_out : out STD_LOGIC;
	   --SF-table signals 
		
		TSF_DS_PortNum : In STD_LOGIC_VECTOR (Input_port_num_bit-1 downto 0);
		TSF_Bcast: in STD_LOGIC;
		TSF_OutputP_ready: In STD_LOGIC; 
		
		SFT_req_out: Out STD_LOGIC;
		SFT_SportN: Out STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0);
		
			
		SFT_SMac_add_out : Out STD_LOGIC_VECTOR(7 downto 0);
		SFT_DMac_add_out : Out STD_LOGIC_VECTOR(7 downto 0);
--    debug output 		
-- 		count_out : Out STD_LOGIC_VECTOR(3 downto 0);
-- 		Mac_reg: Out STD_LOGIC_VECTOR(7 downto 0);
-- 		count_asset: out STD_LOGIC;
--		Dn_reg_en: out STD_LOGIC;
------debug line 
 				
		SFT_RDone: Out STD_LOGIC
    );           
end SF_table_interface;


ARCHITECTURE Behav OF SF_table_interface IS

        TYPE MAC_VECTOR_ARRAY IS ARRAY (MAC_len-1 DOWNTO 0) of STD_LOGIC_VECTOR(7 downto 0);
        Type Mac_table_state is (s0,s1,s3,s4,s5); --s6
        Signal  Add_Fifo_rdreq: STD_LOGIC;
        Signal  OutP_Fifo_wreq: STD_LOGIC;
        Signal  Table_OutP_ready :STD_LOGIC;
        Signal  Mac_current_state: Mac_table_state;
        Signal  Mac_next_state: Mac_table_state;
        Signal  Mac_address :  STD_LOGIC_VECTOR(7 downto 0) ;
        Signal  Dn_Mac :  MAC_VECTOR_ARRAY ;
        SIGNAL  Dn_Mac_reg_en : STD_LOGIC;
        SIGNAL  Counter_sset : STD_LOGIC;
        Signal  Inport_reg_en : STD_LOGIC;
        Signal  Mac_cnter: STD_LOGIC_VECTOR(3 downto 0);
        Signal  Des_O_portNum1 :  STD_LOGIC_VECTOR (output_port_num_bit-2 downto 0);
        Signal  Des_O_portNum2 :  STD_LOGIC_VECTOR (output_port_num_bit-1 downto 0);
        Signal  Sour_P: STD_LOGIC_VECTOR(Input_port_num_bit-1 downto 0) ;
        Signal  SFT_SMac_add : STD_LOGIC_VECTOR(7 downto 0);
		Signal  SFT_DMac_add : STD_LOGIC_VECTOR(7 downto 0);
--		SIGNAL  Outport_reg_en : STD_LOGIC;

        Signal  SFT_req: STD_LOGIC;
Begin
     
      Mac_counter0 : lpm_counter
			GENERIC MAP (LPM_WIDTH => Counter_num_bit,LPM_SVALUE=>"0000")
			PORT MAP (clock => clk,
						sclr => Counter_sset,
						q => Mac_cnter
						);

------- Register for source port number    
    Input_portnum: lpm_ff GENERIC MAP ( LPM_WIDTH => Input_port_num_bit )
                          port map (data=>Rcv_SportN,clock=>clk,enable=>Inport_reg_en,q=>Sour_P);
------- Register for output port number	
--    Output_portnum: lpm_ff GENERIC MAP ( LPM_WIDTH => output_port_num_bit )
--                          port map (data=>Des_O_portNum2,clock=>clk,enable=>Outport_reg_en,q=>Outp_Fifo_Pdata);
		
	


--------Registers for Desination MAC Address
	Dn_Mac_Reg5 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Add_Fifo_data,enable=>Dn_Mac_reg_en,q=>Dn_Mac(5));
	Dn_Mac_Reg4 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(5),enable=>Dn_Mac_reg_en,q=>Dn_Mac(4));
	Dn_Mac_Reg3 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(4),enable=>Dn_Mac_reg_en,q=>Dn_Mac(3));
	Dn_Mac_Reg2 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(3),enable=>Dn_Mac_reg_en,q=>Dn_Mac(2));
	Dn_Mac_Reg1 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(2),enable=>Dn_Mac_reg_en,q=>Dn_Mac(1));
	Dn_Mac_Reg0 : lpm_ff 
	GENERIC MAP ( LPM_WIDTH => Mac_num_bit)
	PORT MAP (clock=>clk,data=>Dn_Mac(1),enable=>Dn_Mac_reg_en,q=>Dn_Mac(0));

	Add_Fifo_rdreq_out<=Add_Fifo_rdreq;
	OutP_Fifo_wreq_out<=OutP_Fifo_wreq;
	Outp_Fifo_Pdata<=Des_O_portNum2;
	SFT_SportN <=Sour_P;
	SFT_req_out <=SFT_req;
	Mac_address<=Add_Fifo_data;
	SFT_SMac_add_out <= SFT_SMac_add;
	SFT_DMac_add_out <= SFT_DMac_add;
	
--	SFT_SMac_add <= (others =>'0');
--	SFT_DMac_add <= (others =>'0');
--	SFT_SMac_add_out <= Mac_address When Mac_current_state = s3 else
--					(others =>'0');
--    SFT_DMac_add_out <= Dn_Mac(conv_integer(Mac_cnter))When Mac_current_state = s3 else
--					(others =>'0');
----debug line	
--	count_asset <=Counter_sset;
--	count_out<=Mac_cnter;
--	Dn_reg_en<=Dn_Mac_reg_en;
--	Mac_reg <=Dn_Mac(5);
----debug end	


		
		PROCESS (clk,reset) --State update process
		BEGIN
		IF ((reset = '1')) THEN --check for reset
			Mac_current_state <= s0;

		ELSIF (clk = '1' AND clk'event) THEN --At the rising edge of clock, update states
			Mac_current_state<= Mac_next_state;
		END IF;
		END PROCESS;
--- Mac_Table SM		
--	Mac_Table :Process (clk,Mac_current_state,Outp_Fifo_full,Add_Fifo_empty,Mac_cnter,TSF_OutputP_ready,Sour_P,TSF_Bcast,Des_O_portNum1,delay)
--	Mac_Table :Process (clk)
	Mac_Table :Process (clk,Mac_current_state,Add_Fifo_empty,Mac_cnter,TSF_OutputP_ready)
		Begin
--       if (clk = '0' AND clk'event) THEN        
                Inport_reg_en <='0';
				Mac_next_state<=Mac_current_state;
				Counter_sset <= '1';	
				  
				Case Mac_current_state Is

					When s0 =>
					  if (Add_Fifo_empty ='0')then
							Mac_next_state <= s1;
					   end if;	
				    When s1 =>
						Counter_sset <= '0';
						if (Mac_cnter ="0101")then
							Mac_next_state <= s3;
							Counter_sset <= '1';
						end if;
						if (Mac_cnter ="0001")then
							Inport_reg_en <='1';
						end if;
						
						
					When s3 =>          ---   send MAC address to the table;
						if (Mac_cnter ="0101")then
							Mac_next_state <= s4;
						end if;
							Counter_sset <= '0';
					When s4 =>
						 if (TSF_OutputP_ready ='1') then
	                        Mac_next_state<=s5;
						 end if;
					When s5 =>
						    Mac_next_state<=s0;
					end case;	
--		end if; 
	End Process Mac_Table;




	
----Output logic	
	Output_logic: process (clk,Mac_current_state,Dn_Mac,Mac_cnter,Mac_address)
    Begin	
		if (clk = '0' AND clk'event) THEN   
				SFT_SMac_add <= (others =>'0');
				SFT_DMac_add <= (others =>'0');
		  
				Dn_Mac_reg_en <='0';
				SFT_req <='0';
				SFT_RDone<='0';
				Add_Fifo_rdreq <='0';
				OutP_Fifo_wreq <='0';

				Des_O_portNum2 <=(others =>'0');
					 
		 case Mac_current_state is
		 When s0=>
		 When s1=>
			 if (Mac_cnter ="0101")then
				SFT_req <='1';
			end if;
			Add_Fifo_rdreq <='1';		
            Dn_Mac_reg_en <='1';
            
         When s3 =>
			SFT_req <='1';
			Add_Fifo_rdreq <='1';
     		SFT_SMac_add <= Mac_address;
			SFT_DMac_add <= Dn_Mac(conv_integer(Mac_cnter));
		 
		 When s4 =>
			SFT_req <='1';
		 When s5 =>
			SFT_req <='1';
--			Outport_reg_en<='1';
			if (TSF_Bcast='1') then
				case Sour_P Is
                When "00" =>
					Des_O_portNum2<="0100";
				When "01" =>
					Des_O_portNum2<="0101";
				When "10" =>
					Des_O_portNum2<="0110";
				When "11" =>	
					Des_O_portNum2<="0111";
				end case;
			else
				if (TSF_DS_PortNum(1 downto 0)=Sour_P) then
					Des_O_portNum2<="10"&TSF_DS_PortNum(1 downto 0);
					else
						Des_O_portNum2<="00"&TSF_DS_PortNum(1 downto 0);
						end if;
			end if;
			OutP_Fifo_wreq<='1';
			SFT_RDone <='1';

		 end case;	
		end if;
   End Process Output_logic;

end Behav;        